/**
 * Created on 12/04/2008
 * 
 */
package com.apbetioli.mapr.project.control;

import com.apbetioli.mapr.place.control.kml.KMLGenerator;
import com.apbetioli.mapr.place.entity.Place;
import com.apbetioli.mapr.project.dao.ProjectsDaoFactory;
import com.apbetioli.mapr.project.dao.ProjectsDaoInterface;
import com.apbetioli.mapr.project.entity.Project;
import com.apbetioli.mapr.project.schema.ProjectsManager;
import com.apbetioli.mapr.project.schema.CtAction;
import com.apbetioli.mapr.project.schema.CtDelete;
import com.apbetioli.mapr.project.schema.CtFindByKey;
import com.apbetioli.mapr.project.schema.CtFindByName;
import com.apbetioli.mapr.project.schema.CtListAll;
import com.apbetioli.mapr.project.schema.CtProject;
import com.apbetioli.mapr.project.schema.CtResponse;
import com.apbetioli.mapr.project.schema.CtResponseList;
import com.apbetioli.mapr.project.schema.CtSave;
import com.apbetioli.mapr.project.schema.ProjectsManager;
import com.apbetioli.mapr.project.schema.StAction;
import com.apbetioli.mapr.project.schema.StStatus;
import com.apbetioli.mapr.util.ErrorsEnum;
import com.apbetioli.mapr.util.properties.PropertiesLoaderImpl;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * 
 * @author Alexandre Parra Betioli
 */
public final class ProjectsControl {

    private ProjectsDaoInterface projectsDao;
    
    public ProjectsControl() {
        this(true);
    }
    
    //Package private constructor. Used for unit tests.
    ProjectsControl( final boolean useTransactions ) {
        projectsDao = ProjectsDaoFactory.getInstance(useTransactions);
    }
    
    public ProjectsManager process( final ProjectsManager input ) {

        //Validate input
        
        if ( input.getActionList() == null ) {
            ErrorsEnum e = ErrorsEnum.WRONG_INPUT;
            return e.getProjectsManagerError();
        }
        
        //Prepare output
        
        ProjectsManager output       = new ProjectsManager();
        CtResponseList  responseList = new CtResponseList();
        output.setResponseList(responseList);        
        
        //Process
        
        for( CtAction action : input.getActionList().getSaveOrDeleteOrFindByKey() ) {
            CtResponse response = processAction( action );
            responseList.getResponse().add(response);
        }
        
        return output;
    }

    private CtResponse processAction( final CtAction action) {

        CtResponse response = new CtResponse();
        
        if( action instanceof CtSave )
        {
            CtProject proj = ((CtSave)action).getProject();
            if( proj.getKey() == null )
                response = save( (CtSave)action );
            else
                response = update( (CtSave)action );            
        }
        
        else if ( action instanceof CtDelete )
            response = delete( (CtDelete)action );
            
        else if ( action instanceof CtFindByKey )
            response = findByKey( (CtFindByKey) action );

        else if ( action instanceof CtFindByName )
            response = findByName( (CtFindByName) action );
        
        else if ( action instanceof CtListAll )
            response = listAll( (CtListAll) action );
        
        else {
            //All the actions are should be listed above, so else won't be reached.
        }
        
        return response;
    }

    private CtResponse save( final CtSave ctSave) {
        CtResponse response = new CtResponse();
        response.setAction( StAction.SAVE );

        try {
            CtProject ctProject  = ctSave.getProject();
            
            if( getProjectsDao().findByName( ctProject.getName() ) != null ) {
                response.setMessage( PropertiesLoaderImpl.getValue("messages.properties", "project.action.add.fail.nameExists") );
                response.setStatus( StStatus.FAILURE );
                return response;
            }
            
            if( getProjectsDao().findByEmail( ctProject.getEmail() ) != null ) {
                response.setMessage( PropertiesLoaderImpl.getValue("messages.properties", "project.action.add.fail.emailExists") );
                response.setStatus( StStatus.FAILURE );
                return response;
            }
            
            String newKey = KeyGenerator.generateKey( ctProject );
            
            if( getProjectsDao().findByKey( newKey ) != null ) {
                response.setMessage( PropertiesLoaderImpl.getValue("messages.properties", "project.action.add.fail.exists") );
                response.setStatus( StStatus.FAILURE );
                return response;
            }
            
            Project project    = new Project();
            project.parse( ctProject );           
            project.setKey(newKey);
            
            Project old = getProjectsDao().save(project);
            
            if( old == null)
                response.setMessage( PropertiesLoaderImpl.getValue("messages.properties", "project.action.added") );
            else
                response.setMessage( PropertiesLoaderImpl.getValue("messages.properties", "project.action.updated") );

            //Generates empty KML
            
            KMLGenerator kg = new KMLGenerator();
            kg.generate(new LinkedList<Place>(), newKey);
            
            response.getProject().add( project.clone() );
            response.setStatus( StStatus.SUCCESS );
        }
        catch( Exception e ) {
            Logger.getLogger(ProjectsControl.class.getName()).log(Level.SEVERE, null, e);
            response.setMessage( e.getMessage() );
            response.setStatus( StStatus.ERROR );
        }
        
        return response;
    }
    
    private CtResponse update( final CtSave ctSave) {
        CtResponse response = new CtResponse();
        response.setAction( StAction.SAVE );

        try {
            CtProject ctProject  = ctSave.getProject();
            
            if( getProjectsDao().findByKey( ctProject.getKey() ) == null ) {
                response.setMessage( PropertiesLoaderImpl.getValue("messages.properties", "project.action.fail.findByKey") + ": " + ctProject.getKey());
                response.setStatus( StStatus.FAILURE );
                return response;
            }
            
            Project project  = new Project();
            project.parse( ctProject );
            
            Project old = getProjectsDao().save( project );
            
            if( old == null)
                response.setMessage( PropertiesLoaderImpl.getValue("messages.properties", "project.action.added") );
            else
                response.setMessage( PropertiesLoaderImpl.getValue("messages.properties", "project.action.updated") );
            
            response.getProject().add( old.clone() );
            response.getProject().add( project.clone() );
            response.setStatus( StStatus.SUCCESS );
        }
        catch( Exception e ) {
            Logger.getLogger(ProjectsControl.class.getName()).log(Level.SEVERE, null, e);
            response.setMessage( e.getMessage() );
            response.setStatus( StStatus.ERROR );
        }
        
        return response;
    }
    
    private CtResponse delete( final CtDelete ctDelete) {
        CtResponse response = new CtResponse();
        response.setAction( StAction.DELETE );

        try {
            String      key     = ctDelete.getKey();
            Project     deleted = getProjectsDao().delete(key);
            
            if( deleted == null ) {
                response.setMessage( PropertiesLoaderImpl.getValue("messages.properties", "project.action.fail.findByKey") + ": " + key);
                response.setStatus( StStatus.FAILURE );
            }
            else {
                response.setMessage( PropertiesLoaderImpl.getValue("messages.properties", "project.action.deleted") );
                response.getProject().add( deleted.clone() );
                response.setStatus( StStatus.SUCCESS );
            }
            
            //Removes KML file
            
            KMLGenerator kg = new KMLGenerator();
            kg.delete(key);
            
        }
        catch( Exception e ) {
            Logger.getLogger(ProjectsControl.class.getName()).log(Level.SEVERE, null, e);
            response.setMessage( e.getMessage() );
            response.setStatus( StStatus.ERROR );
        }
        
        return response;
    }
    
    private CtResponse findByKey( final CtFindByKey ctFindByKey) {
        CtResponse response = new CtResponse();
        response.setAction( StAction.FIND_BY_KEY );

        try {
            String      key   = ctFindByKey.getKey();
            Project     found = getProjectsDao().findByKey(key);
            
            if( found == null ) {
                response.setMessage( PropertiesLoaderImpl.getValue("messages.properties", "project.action.fail.findByKey") + ": " + key);
                response.setStatus( StStatus.FAILURE );
            }
            else {
                response.setMessage( PropertiesLoaderImpl.getValue("messages.properties", "project.action.findByKey") );
                response.getProject().add( found.clone() );
                response.setStatus( StStatus.SUCCESS );
            }
        }
        catch( Exception e ) {
            Logger.getLogger(ProjectsControl.class.getName()).log(Level.SEVERE, null, e);
            response.setMessage( e.getMessage() );
            response.setStatus( StStatus.ERROR );
        }
        
        return response;
    }
    
    private CtResponse findByName( final CtFindByName ctFindByName) {
        CtResponse response = new CtResponse();
        response.setAction( StAction.FIND_BY_NAME );

        try {
            String      name  = ctFindByName.getName();
            Project     found = getProjectsDao().findByName(name);
            
            if( found == null ) {
                response.setMessage( PropertiesLoaderImpl.getValue("messages.properties", "project.action.fail.findByName") + ": " + name);
                response.setStatus( StStatus.FAILURE );
            }
            else {
                response.setMessage( PropertiesLoaderImpl.getValue("messages.properties", "project.action.findByName" ) );
                response.getProject().add( found.clone() );
                response.setStatus( StStatus.SUCCESS );
            }
        }
        catch( Exception e ) {
            Logger.getLogger(ProjectsControl.class.getName()).log(Level.SEVERE, null, e);
            response.setMessage( e.getMessage() );
            response.setStatus( StStatus.ERROR );
        }
        
        return response;
    }    

    private CtResponse listAll( final CtListAll ctListAll) {
        CtResponse response = new CtResponse();
        response.setAction( StAction.LIST_ALL );

        try {
            List<Project> list = getProjectsDao().listAll();

            int numberOfPlacesFound = 0;
            
            if( list != null ) {
                for( Project project : list ) {
                    response.getProject().add( project.clone() );
                }
                
                numberOfPlacesFound = list.size();
            }
                        
            response.setMessage( PropertiesLoaderImpl.getValue("messages.properties", "project.action.listAll") +  ": " + numberOfPlacesFound);
            response.setStatus( StStatus.SUCCESS );
        }
        catch( Exception e ) {
            Logger.getLogger(ProjectsControl.class.getName()).log(Level.SEVERE, null, e);
            response.setMessage( e.getMessage() );
            response.setStatus( StStatus.ERROR );
        }
        
        return response;
    }

    public ProjectsDaoInterface getProjectsDao() {
        return projectsDao;
    }
    
}
